import re
import json
import os
import sys
import clang.cindex
from clang.cindex import CursorKind

from utils import is_system_function_declaration, LLVM_LIBRARY_PATH, clang_options, collect_include_paths, system_header_paths

def is_target_file(cursor, target_file):
    """
    判断当前节点是否属于目标文件
    """
    return cursor.location.file and cursor.location.file.name == target_file

def normalize_type(type_name):
    """
    规范化类型名称，去除struct、enum、union等前缀，并过滤基本类型和指针类型
    """
    # 过滤基本类型和指针类型
    basic_types = {
        "int", "char", "short", "long", "float", "double", "void",
        "int*", "char*", "short*", "long*", "float*", "double*", "void*",
        "int *", "char *", "short *", "long *", "float *", "double *", "void *"
    }

    if type_name in basic_types:
        return None  # 过滤掉基本类型和指针类型

    # 去除const、static等修饰符
    type_name = type_name.replace("const ", "").replace("static ", "").strip()
    type_name = type_name.replace("[]", "")
    # 去除指针符号（如int* -> int, int * -> int）
    if "*" in type_name:
        type_name = type_name.replace("*", "").strip()  # 去除所有*符号

    # 去除struct、enum、union等前缀
    if type_name.startswith(('struct ', 'enum ', 'union ')):
        return type_name.split(' ', 1)[1]  # 去除前缀

    return type_name

def extract_symbols_from_function(cursor):
    """
    从函数体的AST中提取符号信息
    """
    symbols = set()

    # 遍历函数体的所有子节点
    for node in cursor.walk_preorder():
        # 跳过非目标文件的节点
        if not is_target_file(node, cursor.location.file.name):
            continue
        
        # 提取参数和局部变量的符号信息
        if node.kind in [CursorKind.PARM_DECL, CursorKind.VAR_DECL]:
            symbol_name = node.spelling
            symbols.add(symbol_name)
            symbol_type = normalize_type(node.type.spelling)  # 规范化类型名称
            if symbol_type:
                symbols.add(symbol_type) 

        # 提取符号信息
        if node.kind in [
            CursorKind.DECL_REF_EXPR,      # 变量引用
            CursorKind.CALL_EXPR,         # 函数调用
            CursorKind.TYPE_REF,           # 类型引用
            CursorKind.MEMBER_REF_EXPR,    # 成员引用
            CursorKind.FIELD_DECL,
            CursorKind.ENUM_CONSTANT_DECL,
            CursorKind.UNEXPOSED_EXPR,
            CursorKind.BINARY_OPERATOR,
            CursorKind.UNARY_OPERATOR,
        ]:
            symbols.add(node.spelling)
    symbol_lst = list(symbols)
    symbol_lst = [symbol for symbol in symbol_lst if symbol]
    return symbol_lst 

def extract_functions_from_file(file_path, include_dirs):
    # 初始化clang库
    if not clang.cindex.Config.loaded:
        clang.cindex.Config.set_library_path(LLVM_LIBRARY_PATH)  # 修改为libclang路径
    index = clang.cindex.Index.create()
    # 构建编译参数，设置包括目录
    args = ['-I' + include_dir for include_dir in include_dirs]

    tu = index.parse(file_path, args=args, options=clang_options)
    functions = []

    # 遍历AST，找到函数定义节点
    for node in tu.cursor.get_children():
        if is_system_function_declaration(node):
            continue
        if node.kind == CursorKind.FUNCTION_DECL and is_target_file(node, file_path):
            function_name = node.spelling
            functions.append((function_name, node))

    return functions

def extract_symbols_entry(c_file_path, include_dirs=[]):
    """
    主函数
    """
    # 提取函数定义
    functions = extract_functions_from_file(c_file_path, include_dirs)

    func_symbols = []
    # 遍历每个函数，提取符号信息并更新JSON文件
    for function_name, function_node in functions:
        symbols = extract_symbols_from_function(function_node)
        symbols.append(function_name)
        func_symbols.append((function_name, symbols))

    return func_symbols

if __name__ == "__main__":
    if len(sys.argv) < 2:
        print("Usage: python extract_symbols.py <c_file_path> [include_dirs]")
        sys.exit(1)

    c_file_path = sys.argv[1]
    include_dirs = sys.argv[2]

    extract_symbols_entry(c_file_path, include_dirs)
